package com.llu.serial.fastjson;

import com.llu.serial.fastjson.serializer.FieldSerializer;

import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class Utils {

    /**
     * 判断给定的类型是否为包装类
     *
     * @param type 要判断的类型
     * @return 如果给定的类型为包装类，则返回true；否则返回false
     */
    public static boolean isBox(Class type) {
        return type == Integer.class ||
                type == Character.class ||
                type == Byte.class ||
                type == Boolean.class ||
                type == Double.class ||
                type == Float.class ||
                type == Short.class;
    }


    /**
     * 判断给定的类型是否为字符串类型
     * <p>
     * 此方法通过检查给定的类型是否可以赋值为CharSequence类的实例来判断该类型是否为字符串类型
     * 它不直接比较类型，而是使用isAssignableFrom方法来判断，这允许类型为String或其他实现了CharSequence接口的类
     *
     * @param type 要判断的类型，它可以是任何类或接口类型
     * @return 如果给定的类型是字符串类型（CharSequence类的子类或实现了CharSequence接口），则返回true；否则返回false
     */
    public static boolean isString(Class type) {
        return CharSequence.class.isAssignableFrom(type);
    }



    /**
     * 获得对于class包括父class所有的成员属性
     *
     * @param clazz 要解析的类
     * @return 包含所有字段的映射，其中键是字段名，值是字段对象
     */
    public static Map<String, Field> parserAllFieldToCache(Map<String, Field> fieldCacheMap, Class<?> clazz) {
        //获得自己的所有属性
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            //避免重复字段
            if (!fieldCacheMap.containsKey(fieldName)) {
                fieldCacheMap.put(fieldName, field);
            }
        }
        //查找父类 的属性
        if (clazz.getSuperclass() != null && clazz.getSuperclass() != Object.class) {
            parserAllFieldToCache(fieldCacheMap, clazz.getSuperclass());
        }
        return fieldCacheMap;
    }


    /**
     * 计算需要序列化的成员
     * 包括：当前类及其父类中的getter方法和public成员属性
     *
     * @param clazz         要计算序列化成员的类
     * @param fieldCacheMap 字段缓存映射，用于存储字段名到Field对象的映射
     * @return List<FieldSerializer> 序列化成员列表
     */
    public static List<FieldSerializer> computeGetters(Class<?> clazz, Map<String, Field> fieldCacheMap) {
        Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<>();

        // 获取当前类或父类的所有方法（包括Java SDK中的方法）
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            String methodName = method.getName();

            // 忽略静态方法
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }

            // 忽略返回类型为void的方法
            if (method.getReturnType().equals(Void.TYPE)) {
                continue;
            }

            // 忽略有参数的方法
            if (method.getParameterTypes().length != 0) {
                continue;
            }

            // 忽略名为getClass的方法
            if (methodName.equals("getClass")) {
                continue;
            }

            String propertyName;
            // 处理以"get"开头的方法
            if (methodName.startsWith("get")) {
                if (methodName.length() < 4) {
                    continue;
                }
                char c3 = methodName.charAt(3);
                propertyName = Character.toLowerCase(c3) + methodName.substring(4);
                Field field = fieldCacheMap.get(propertyName);
                FieldInfo fieldInfo = new FieldInfo(propertyName, method, field);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
            // 处理以"is"开头的Boolean类型方法
            if (methodName.startsWith("is")) {
                if (methodName.length() < 3) {
                    continue;
                }
                if (method.getReturnType() != Boolean.TYPE && method.getReturnType() != Boolean.class) {
                    continue;
                }
                char c2 = methodName.charAt(2);
                propertyName = Character.toLowerCase(c2) + methodName.substring(3);
                if (fieldInfoMap.containsKey(propertyName)) {
                    continue;
                }
                Field field = fieldCacheMap.get(propertyName);
                FieldInfo fieldInfo = new FieldInfo(propertyName, method, field);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
        }

        // 获取类的所有public成员属性（包括父类的）
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            String propertyName = field.getName();
            if (!fieldInfoMap.containsKey(propertyName)) {
                FieldInfo fieldInfo = new FieldInfo(propertyName, null, field);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
        }

        // 将FieldInfo对象转换为FieldSerializer对象列表
        List<FieldSerializer> fieldInfos = new ArrayList<>();
        for (FieldInfo fieldInfo : fieldInfoMap.values()) {
            fieldInfos.add(new FieldSerializer(fieldInfo));
        }
        return fieldInfos;
    }


    /**
     * 反序列化 采集公有set函数与公有属性
     *
     * @param clazz
     * @param fieldCacheMap
     * @return
     */
    public static List<FieldInfo> computeSetters(Class clazz, Map<String, Field> fieldCacheMap) {
        Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<>();
        //类(父类) 所有的公有函数
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            String methodName = method.getName();
            if (Modifier.isStatic(method.getModifiers())) {
                continue;
            }
            if (!method.getReturnType().equals(Void.TYPE)) {
                continue;
            }
            if (method.getParameterTypes().length != 1) {
                continue;
            }
            String propertyName;
            if (methodName.startsWith("set")) {
                if (methodName.length() < 4) {
                    continue;
                }
                //set后的第一个字母
                char c3 = methodName.charAt(3);
                propertyName = Character.toLowerCase(c3) + methodName.substring(4);
                Field field = fieldCacheMap.get(propertyName);
                FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, true);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
        }

        //所有的public成员
        for (Field field : clazz.getFields()) {
            int modifiers = field.getModifiers();
            //静态和final的不要
            if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                continue;
            }
            String propertyName = field.getName();
            //把公有成员也加入
            if (!fieldInfoMap.containsKey(propertyName)) {
                FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, true);
                fieldInfoMap.put(propertyName, fieldInfo);
            }
        }


        List<FieldInfo> fieldInfos = new ArrayList<>();
        //fieldinfo加入到list集合中
        for (FieldInfo fieldInfo : fieldInfoMap.values()) {
            fieldInfos.add(fieldInfo);
        }
        return fieldInfos;
    }

    /**
     * 获得
     *
     * @param fieldType
     * @return
     */
    public static Type getItemType(Type fieldType) {

        if (fieldType instanceof ParameterizedType) {
            Type actualTypeArgument = ((ParameterizedType) fieldType)
                    .getActualTypeArguments()[0];
            // 泛型 获得上限 <? extends String> 则获得String
            if (actualTypeArgument instanceof WildcardType) {
                WildcardType wildcardType = (WildcardType) actualTypeArgument;
                Type[] upperBounds = wildcardType.getUpperBounds();
                if (upperBounds.length == 1) {
                    actualTypeArgument = upperBounds[0];
                }
            }
            return actualTypeArgument;
        }
        return Object.class;
    }
}